package com.apache.passport.common;

import com.apache.api.vo.ResultEntity;
import com.apache.passport.jwt.CorsFilter;
import com.apache.tools.ConfigUtil;
import com.apache.tools.StrUtil;
import com.apache.uct.common.ToolsUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * description:单点登录客户端过滤器
 *
 * @author dyh 创建时间：2018年02月13日
 */
public class JwtClientFilter extends CorsFilter {

    private static final Logger logg = LoggerFactory.getLogger(JwtClientFilter.class);

    protected String jwtOrgEname = "";

    private String sysCode = "";

    private Map<String, ArrayList<String>> whiteMap = new HashMap();

    public void init(FilterConfig config) {
        sysCode = config.getInitParameter("sysCode");
        //XmlWhiteUtils.getInstance().deWhiteXml(this.whiteMap, sysCode);
        super.init(config);
        this.jwtOrgEname = ToolsUtil.getInstance().getValueByKey("jwt_orgEname");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
            FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        resp.setCharacterEncoding("UTF-8");
        resp.setDateHeader("expires", 0);
        resp.setHeader("Cache-Control", "no-cache");
        resp.setHeader("pragma", "no-cache");
        req.setCharacterEncoding("UTF-8");

        resp.setHeader("Access-Control-Allow-Origin", "*");
        resp.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        resp.setHeader("Access-Control-Max-Age", "3600");
        resp.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept, token");

        String path_ = req.getContextPath();
        String basePath_ =
                req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + path_
                        + "/";
        //设置退出路径  页面中直接${outUrl}即可
        req.getSession().setAttribute("outUrl", basePath_);
        String uri = req.getRequestURI();//获取uri信息
        String suffix = PassportHelper.getInstance().parseUrlSuffix(uri);//获取后缀名
        if (StrUtil.isNotNull(suffix)) {//如果存在后缀为图片,css等格式,直接跳过,不拦截
            suffix = suffix.toLowerCase();//后缀名小写
            if (XmlWhiteUtils.SUFFIX.contains(suffix)) {
                filterChain.doFilter(req, resp);
                return;
            }
        }
        if(StrUtil.isNotNull(req.getHeader("zuultokenid"))){//从zuul过来的不做后继验证
            filterChain.doFilter(req, resp);
            return;
        }
        /**监控白名单处理*/
        if(jkWhite(req.getServletPath())){
            filterChain.doFilter(req, resp);
            return;
        }
        //获取token
        String tokenCookie = PassportHelper.getInstance().getCurrCookie(req);
        //获取访问路径
        String path = req.getContextPath();
        //如果客户端根据token访问获取
        String pkt = req.getParameter("tokenId");
        if ("undefined".equalsIgnoreCase(pkt))
            pkt = "";
        String tokenId = StrUtil.doNull(tokenCookie,pkt);
        boolean tokenMark = false;
        if (ConfigUtil.getInstance().checkFileUpdate("") || StrUtil.isNull(cookieName)) {
            initValue();
        }

        if (!uri.equals(path + "/logout") && !uri.equals(path + "/cset")) {
            String code = req.getParameter("code");
            //是否用jwt验证
            if ("T".equals(ToolsUtil.getInstance().getValueByKey("if_jwt_check"))) {
                if (StrUtil.isNotNull(code)) {
                    tokenId = getAccessToken(code, req, resp);
                }
            }
            if (StrUtil.isNotNull(tokenId)) {
                tokenMark = auditTokenAndSso(tokenId, req, resp);
            }
        }
        String loginUrl = "";
        if (!tokenMark) {
            String config_custom_login = ToolsUtil.getInstance().getLocalByKey("config.properties","custom_login");
            if(StrUtil.isNull(config_custom_login)) {
                loginUrl = getLonginUrl(req, resp, tokenId);
            }else{
                loginUrl = config_custom_login;
            }
        }

        if (req.getRequestURI().equals(path + "/logout")) {
            doLogout(req, resp, filterChain, tokenId, loginUrl);
        } else if (req.getRequestURI().equals(path + "/cset")) {
            setCookie(req, resp);//设置cookie
        } else {
            if (tokenMark) {
                filterChain.doFilter(req, resp);
                return;
            } else {
                if (!StrUtil.isNull(tokenId)) {
                    clearCookie(tokenId, req, resp, "/");
                }
                boolean mark = whitePathFiter(uri, req);//白名单处理
                if (mark) {
                    filterChain.doFilter(req, resp);
                    return;
                } else {
                    resp.sendRedirect(loginUrl);
                }
            }
        }
    }

    /**
     * description: 白名单验证
     */
    protected boolean whitePathFiter(String uri, HttpServletRequest req) {
        //初始化白名单
        String path = req.getServletPath();
        XmlWhiteUtils.getInstance().deWhiteXml(whiteMap, sysCode);
        String whiteUrl = "/error.action,/errorPage,";
        /**白名单处理*/
        if (StrUtil.isNotNull(whiteUrl)) {
            String[] wus = whiteUrl.split(",");
            for (int i = 0; i < wus.length; i++) {
                String wurl = wus[i];
                if (StrUtil.isNotNull(wurl)) {
                    if (path.startsWith(wurl)) {
                        return true;
                    }
                }
            }
        }
        ArrayList<String> whiteUrl2 = whiteMap.get("whiteUrl");
        ArrayList<String> whiteParadigm = whiteMap.get("whiteParadigm");
        String ctx = req.getContextPath(); //获取上下文，如/项目名
        uri = uri.substring(ctx.length());
        //url白名单
        if (whiteUrl2.contains(uri)) {
            return true;
        } else {
            int wp = whiteParadigm.size();
            if (uri.length() > 1) {//主要是/造成,如guo/后面有内容,则进入以下方法
                for (int i = 0; i < wp; i++) {
                    if ((whiteParadigm.get(i)).contains("*")) {
                        String wdir = (whiteParadigm.get(i)).replace("*", "");
                        int s = uri.indexOf(wdir);
                        if (s == 0) {
                            return true;
                        }
                    } else {
                        if (!"".equals(whiteParadigm.get(i))) {
                            int s = uri.indexOf(whiteParadigm.get(i));
                            if (s == 0) {
                                return true;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * description:  用户退出操作
     */
    protected void doLogout(HttpServletRequest req, HttpServletResponse resp, FilterChain chain,
            String tokenCookie, String loginUrl) {
        try {
            if (StrUtil.isNull(tokenCookie)) {
                clearCookie("", req, resp, "/");
                resp.sendRedirect(loginUrl);
                return;
            }
            long startlong = System.currentTimeMillis();
            String userEname = PassportHelper.getInstance().getCurrCookie(req, "_uc.sso");
            if (StrUtil.isNull(userEname)) {
                userEname = (String) req.getSession().getAttribute("message");
            }

            ResultEntity entity = this
                    .checkToken(tokenCookie, req.getLocalAddr(), "logout", userEname);
            if ("true".equals(entity.getResult())) {
                clearCookie(tokenCookie, req, resp, "/");
                log.warn("logout : userEname=" + userEname + ";" + (System.currentTimeMillis()
                        - startlong));
            } else {
                log.warn("与统一登录系统通讯失败,操作[证书认证]失败");
            }
            if (tokenCookie.indexOf("uni_") == -1) {
                resp.sendRedirect(loginUrl);
            } else {
                String csetUrl = getLonginUrl(req, resp, "");
                resp.sendRedirect(csetUrl);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    /**
     * description:  清空本地cookie
     */
    protected void clearCookie(String tokenId, HttpServletRequest request,
            HttpServletResponse response, String path) {
        Cookie[] cookies = request.getCookies();
        try {
            if (null != cookies && cookies.length > 0) {
                for (int i = 0; i < cookies.length; i++) {
                    Cookie cookie = new Cookie(cookies[i].getName(), null);
                    cookie.setMaxAge(0);
                    cookie.setPath("/");
                    cookie.setPath(path);//根据你创建cookie的路径进行填写
                    response.addCookie(cookie);
                }
            }
        } catch (Exception ex) {
            log.error("清空Cookies发生异常!" + ex.getMessage());
        }
        if (!"0".equals(isClearSession)) {
            Enumeration enumer = request.getSession().getAttributeNames();
            while (enumer.hasMoreElements()) {
                request.getSession().removeAttribute(enumer.nextElement().toString());
            }
            request.getSession().invalidate();
        }
    }
}
